#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>

/*
 * Params:      k: array of possible action cards
 * Description: This function generate and integer representing a
 *              randomly choosen action card.
 * Return:      Returns the random integer representing action card.
 */
int randomActionCard(int* k, int length)
{
	//set up random number generator
	int seed = 1000;
	SelectStream(1);
	PutSeed((long)seed);

	//Initialization
	int position = rand() % (length - 1);
	int result = k[position];	

	return result;
}

/*
 * Params: G:				  Game State to Initialize
 *		   shouldBeHandCount: address of variable which will be used
 *		                      to assert what the hand count should be
 * Description: This function initializes a random gameState.
 * Return: None. Game State and "Should Be" values can be 
 *         accessed else where after function completed.
 */
void initializeRandomGameState(struct gameState *G, int* shouldBeHandCount)
{
	//set up random number generator
	int seed = 1000;
	SelectStream(1);
	PutSeed((long)seed);

	//Initialization
	int i = 0;
	int player = 0;
	int numPlayers = 1;
	int numEstateCards = 3;
	int numCopperCards = 10;   
	int numActionCards = rand() % 10;   //random number of action (0-10)
	int numHandCount = 4;				//hand count is 5 but set to 4 since array 
	int newEnd1 = 0;
	int newEnd2 = 0;
	int k[10] = {adventurer, council_room, feast, gardens, mine,
		         remodel, smithy, village, baron, great_hall};
	int length = 10;
		
	//clear gameState
	memset(G, 23, sizeof(struct gameState));

	//set number of players and player turn
	G->numPlayers = numPlayers;
	G->whoseTurn = player;
	
	//set player deck with copper 
	G->deckCount[player] = 0;
	for(i = 0; i < numEstateCards; i++)
	{
		G->deck[player][i] = estate;
		G->deckCount[player]++;
	}
	//set player deck with estate
	newEnd1  = numCopperCards + numEstateCards;
	for(i = numEstateCards; i < newEnd1; i++)
	{
		G->deck[player][i] = copper;
		G->deckCount[player]++;
	}
	//set player deck with action 
	newEnd2 = numCopperCards + numActionCards;
	for(i = numCopperCards; i < newEnd2; i++)
	{
		G->deck[player][i] = randomActionCard(k, length); 
		G->deckCount[player]++;
	}
	//shuffle player decks
	if(shuffle(player, G) < 0)
	{
		printf("Shuffling Error\n");
		exit(EXIT_FAILURE);
	}

	//set discard pile to 0	
	G->discardCount[player] = 0;
	
	//set player hand
	G->handCount[player] = numHandCount; 
	G->hand[player][0] = randomActionCard(k, length);
	G->hand[player][1] = randomActionCard(k, length);
	G->hand[player][2] = randomActionCard(k, length);
	G->hand[player][3] = randomActionCard(k, length);
	G->hand[player][4] = adventurer;
	
	//set "Should Be" variables
	*shouldBeHandCount = numHandCount + 2; //+ 2 (+1 for array correction 
										   //     +2 treasure cards should 
										   //     -1 get rid of adventurer card) 
}

void randomAdventurerTest()
{
	//Initialization
	int i = 0;
	int iterationCount = 0;
	int player = 0;
	int randomTesterCount = 1000;
	int shouldBeHandCount = 0;
	int notNeeded = 0;
	int handPos = 4; 				//last card added
	struct gameState G;

	while(iterationCount < randomTesterCount)
	{
		iterationCount++;
		initializeRandomGameState(&G, &shouldBeHandCount);
		cardEffect(adventurer, notNeeded, notNeeded, notNeeded, &G, handPos, &notNeeded);
		printf("Iteration %d out of %d ", iterationCount, randomTesterCount);
		assert(G.handCount[player] == shouldBeHandCount); //checks hand count
		
		//check that the last two inserted hand cards are treasure cards
		int treasureCard1 = G.hand[player][G.handCount[player] - 1];
		int treasureCard2 = G.hand[player][G.handCount[player] - 2];
		assert(treasureCard1 == copper || treasureCard1 == gold 
			   || treasureCard1 == silver);
		assert(treasureCard2 == copper || treasureCard2 == gold 
			   || treasureCard2 == silver);
	    	

		printf("passed!\n");
	}
	printf("Random Tester Passed!\n");

}

int main ()
{
	srand(time(NULL));
	randomAdventurerTest();
	return 0;
}
